package com.cloudweb.oa.utils;

import cn.js.fan.web.Global;
import com.cloudwebsoft.framework.util.LogUtil;
import com.cloudwebsoft.framework.util.OSUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.html.simpleparser.HTMLWorker;
import com.itextpdf.text.html.simpleparser.StyleSheet;
import com.itextpdf.text.pdf.*;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.htmlparser.Parser;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.ImageTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import javax.servlet.http.HttpServletResponse;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Objects;

public class PdfUtil {

    public static String changeImgUrl(String content) {
        // 将图片转为绝对路径
        String contentTmp = content;
        Parser parser;
        try {
            parser = new Parser(content);
            parser.setEncoding("utf-8");//
            TagNameFilter filter = new TagNameFilter("img");
            NodeList nodes = parser.parse(filter);
            if (nodes != null || nodes.size() > 0) {
                StringBuffer sb = new StringBuffer();
                int lastNodeEnd = 0;
                for (int k=0; k<nodes.size(); k++) {
                    ImageTag node = (ImageTag) nodes.elementAt(k);

                    // image/png;base64,
                    String imgUrl = node.getImageURL();
                    int p = imgUrl.indexOf("http");
                    if (p == -1) {
                        if (!imgUrl.startsWith("/")) {
                            imgUrl = Global.getRealPath() + imgUrl;
                        }
                        else {
                            imgUrl = Global.getRealPath().substring(0, Global.getRealPath().length()-1) + imgUrl;
                        }
                        node.setImageURL("file:///" + imgUrl);

                        /*
                        if (imgUrl.startsWith("/")) {
                            imgUrl = Global.getFullRootPath() + imgUrl;
                        }
                        else {
                            imgUrl = Global.getFullRootPath() + "/" + imgUrl;
                        }
                        node.setImageURL(imgUrl);
                        */

                        int s = node.getStartPosition();
                        int e = node.getEndPosition();
                        String c = contentTmp.substring(lastNodeEnd, s);
                        c += node.toHtml();
                        sb.append(c);
                        lastNodeEnd = e;
                    }
                    else {
                        int e = node.getEndPosition();
                        String c = contentTmp.substring(lastNodeEnd, e);
                        sb.append(c);
                        lastNodeEnd = e;
                    }
                }
                sb.append(StringUtils.substring(contentTmp, lastNodeEnd));
                content = sb.toString();
            }
        } catch (ParserException e) {
            LogUtil.getLog(PdfUtil.class).error(e);
        }
        return content;
    }

    /**
     * 将文件柜中的html转为pdf
     * @param response
     * @param title
     * @param content
     * @param author
     */
    public static void htmlToPdf(HttpServletResponse response, String title, String content, String author) {
        try {
            com.itextpdf.text.Document document = new com.itextpdf.text.Document(PageSize.A4);
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            PdfWriter writer = PdfWriter.getInstance(document, buffer);

            document.open();

            document.addTitle(title);// 标题
            document.addAuthor("author");// 作者
            /*document.addSubject("Subject");// 主题
            document.addKeywords("Keywords");// 关键字
            document.addCreator("Creator");// 创建者*/

            // 用XMLWorker方法，本机没问题，但服务器上会存在中文不能显示的问题（仅能显示h2标题）
            /*CSSResolver cssResolver = XMLWorkerHelper.getInstance().getDefaultCssResolver(false);
            FileRetrieve retrieve = new FileRetrieveImpl(Global.getRealPath());
            cssResolver.setFileRetrieve(retrieve);

            // HTML
            HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
            htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
            htmlContext.setImageProvider(new AbstractImageProvider() {
                @Override
                public String getImageRootPath() {
                    return Global.getRealPath();
                }
            });
            htmlContext.setLinkProvider(new LinkProvider() {
                @Override
                public String getLinkRoot() {
                    return Global.getRealPath();
                }
            });

            // Pipelines
            PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
            HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
            CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

            // body中加样式后表格内的中文能显示了，但是其它地方的中文不能显示
            content = "<html><head></head><body style=\"font-family: SimSun;\">" + content + "</body></html>";
            // XML Worker
            XMLWorker worker = new XMLWorker(css, true);
            XMLParser p = new XMLParser(worker);
            p.parse(new StringReader(content));*/

            // 将图片路径改为本地路径file:///
            content = changeImgUrl(content);
            try {
                XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                        new ByteArrayInputStream(content.getBytes("utf-8")),
                        null,
                        Charset.forName("UTF-8"), new AsianFontProvider());
            } catch (IOException e) {
                LogUtil.getLog(PdfUtil.class).error(e);
            }

            // 不能放在finally块中，要放在buffer.toByteArray()前，否则生成的pdf将无法打开
            document.close();

            DataOutput output = new DataOutputStream(response.getOutputStream());
            byte[] bytes = buffer.toByteArray();
            response.setContentLength(bytes.length);
            for (int x=0; x<bytes.length; x++) {
                output.writeByte(bytes[x]);
            }
        } catch (Exception e) {
            LogUtil.getLog(PdfUtil.class).error(e);
        }
    }

    public static void addWatermark(String inputFile, String outputFile, String waterMarkName) {
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            // 水印的高和宽（参数可调节）
            int textH = 75;
            int textW = 170;
            // 间隔距离（参数可调节）
            int interval = 30;
            String owerPwd = "111";
            String userWpd = "222";
            reader = new PdfReader(inputFile);
            PdfReader.unethicalreading = true;
            stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
            //userWpd 文件加密（打开文件密码）；owerPwd 操作加密（文件操作密码）； permissions = 4 能打印不能复制
            //stamper.setEncryption(userWpd.getBytes(),owerPwd.getBytes(),4,false);
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.2f);
            gs.setStrokeOpacity(0.4f);
            int total = reader.getNumberOfPages() + 1;
            JLabel label = new JLabel();
            label.setText(waterMarkName);
            PdfContentByte under;

            Rectangle pageRect = null;
            FontMetrics metrics;
            label.setText(waterMarkName);
            metrics = label.getFontMetrics(label.getFont());
            for (int i = 1; i < total; i++) {
                pageRect = reader.getPageSizeWithRotation(i);
                // 在内容上方加水印
                under = stamper.getOverContent(i);
                // 在内容下方加水印
                //under = stamper.getUnderContent(i);
                under.saveState();
                under.setGState(gs);
                under.beginText();
                under.setFontAndSize(base, 20);
                // 水印文字成30度角倾斜
                for (int height = interval + textH; height < pageRect.getHeight();
                     height = height + textH * 3) {
                    for (int width = interval + textW; width < pageRect.getWidth() + textW;
                         width = width + textW * 2) {
                        under.showTextAligned(Element.ALIGN_LEFT
                                , waterMarkName, width - textW,
                                height - textH, 30);
                    }
                }
                under.endText();
            }
        } catch (DocumentException | IOException e) {
            LogUtil.getLog(PdfUtil.class).error(e);
        } finally {
            if (stamper != null) {
                try {
                    stamper.close();
                } catch (DocumentException | IOException e) {
                    LogUtil.getLog(PdfUtil.class).error(e);
                }
            }
            if (reader != null) {
                reader.close();
            }
        }
    }

    /**
     * 校验PDF文件是否包含js脚本
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static boolean containsJavaScript(File file) {
        PDDocument pdDocument = null;
        try {
            // 加载PDF文件
            pdDocument = PDDocument.load(file, (String) null);
            // 获取文件文档目录中JavaScript,不存在直接校验通过
            PDDocumentNameDictionary names = pdDocument.getDocumentCatalog().getNames();
            if (Objects.isNull(names) || Objects.isNull(names.getJavaScript())) {
                return false;
            }

            // 如果存在JavaScript目录,定义为存在恶意脚本
            if (Objects.nonNull(names.getJavaScript())) {
                return true;
            }

            // 兜底方案:全目录搜索JavaScript、JS
            String CosName = pdDocument.getDocument().getTrailer().toString();
            if (CosName.contains("COSName{JavaScript}") || CosName.contains("COSName{JS}")) {
                return true;
            }
        } catch (Exception e) {
            LogUtil.getLog(PdfUtil.class).error(e);
            // 文件如果不存在，当启用obs时，copyToLocalFile因为延迟时间不足，可能会导致获取不到，应返回 false ，防止文件被误删除
            return false;
        } finally {
            if (pdDocument != null) {
                try {
                    pdDocument.close();
                } catch (IOException e) {
                    LogUtil.getLog(PdfUtil.class).error(e);
                }
            }
        }
        return false;
    }

    public static void main(String[] args) {
        addWatermark("d:/a.pdf", "d:/b.pdf", "内部使用");
    }

}